【进阶表格】灵活的Slot传参(兼容column&table)
基础表格组件封装完成后,实际业务中经常会遇到需要自定义列内容的需求——比如某一列需要显示开关、标签、操作按钮等。Element Plus 的 el-table-column 通过 #default 作用域插槽提供行数据,但如何在封装后的 VTable 组件中透传这些插槽,是需要精心设计的。
作用域插槽的透传问题
在 VTable 组件中,el-table-column 通过 v-for 遍历 columns 配置生成。用户无法直接在 VTable 上写 el-table-column 的插槽,需要通过 VTable 的 props 传递渲染函数或组件。
方案一:渲染函数(render function)
interface ColumnConfig extends TableColumnType {
render?: (scope: { row: any; column: any; $index: number }) => VNode
}
typescript
在模板中使用:
<el-table-column v-for="col in columns" :key="col.prop">
<template #default="scope">
<component :is="col.render(scope)" v-if="col.render" />
<span v-else>{{ scope.row[col.prop!] }}</span>
</template>
</el-table-column>
vue
方案二:Slot 名称约定
约定列的插槽名称为 column-${prop}:
<!-- 用户使用 -->
<VTable :columns="columns">
<template #column-status="{ row }">
<el-tag :type="row.status === 1 ? 'success' : 'danger'">
{{ row.status === 1 ? '启用' : '禁用' }}
</el-tag>
</template>
</VTable>
vue
VTable 内部透传:
<el-table-column v-for="col in columns" :key="col.prop">
<template #default="scope">
<slot :name="`column-${col.prop}`" v-bind="scope">
{{ scope.row[col.prop!] }}
</slot>
</template>
</el-table-column>
vue
移动端表格适配
表格在移动端面临的核心问题是:列太多导致水平溢出。解决方案:
| 方案 | 说明 | 适用场景 |
|---|---|---|
| 横向滚动 | el-table 的 max-height + 横向滚动 | 列数 < 10 |
| 卡片布局 | 每行数据渲染为卡片,字段竖排 | 列数 > 10 |
| 关键列优先 | 移动端只显示关键列,其余点击展开 | 大部分场景 |
safe-area 处理
在 iOS 的刘海屏设备上,需要考虑安全区域(safe area):
/* 适配 iPhone 底部安全区域 */
padding-bottom: env(safe-area-inset-bottom);
css
在 Vite 配置中设置 viewport meta:
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
html
viewport-fit=cover 让页面内容延伸到安全区域外,然后通过 env(safe-area-inset-*) CSS 函数调整内边距。
双重滚动问题
当页面和表格都有自己的滚动容器时,会出现双重滚动。解决方案是确保只有一个滚动容器:
/* 页面容器 */
.page-container {
height: 100vh;
overflow: hidden;
}
/* 内容区域 */
.content-area {
height: calc(100vh - header-height);
overflow-y: auto;
}
/* 表格区域 */
.table-area {
height: 100%;
overflow: hidden; /* 表格自己管理滚动 */
}
css
本节小结
- Slot 透传:通过动态 slot 名称(
column-${prop})将用户自定义内容透传到对应的el-table-column。 - 移动端适配:横向滚动、卡片布局、关键列优先三种方案。
- safe-area:使用
env(safe-area-inset-bottom)和viewport-fit=cover适配 iOS 刘海屏。 - 双重滚动:确保页面只有一个滚动容器,避免嵌套滚动。
↑